<!--
 * @description 组件
 * @author: 陈陈
 * @date: 2025/05/09
 * @phone: 18560000860
 * @email: 18560000860@qq.com
 * @company: 济南晨霜信息技术有限公司 /
 * @business: 承接前后端项目的开发
-->
<template>
	<view
		class="pure-rate"
		:class="_classes"
		:style="_styles"
		@touchstart="_handleTouchStart"
		@touchmove="_handleTouchMove"
		@touchend="_handleTouchEnd"
		:id="_uuid"
	>
		<view
			class="pure-rate__item"
			:class="_calcItemClasses(_i)"
			v-for="_i in count"
			:key="_i"
			:hover-class="hoverClass"
		>
			<view class="pure-rate__icon pure-rate__icon--default">
				<pure-icon
					:name="iconName"
					hover-class=""
				></pure-icon>
			</view>
			<view
				class="pure-rate__icon pure-rate__icon--fill"
				v-if="_showFillIcon(_i)"
				:style="_caleFillIconStyles(_i)"
			>
				<pure-icon
					:name="fillIconName"
					hover-class=""
				></pure-icon>
			</view>

			<!-- 用两个半块监听点击事件，不做整个点击后再根据点击位置判断点击的是左侧还是右侧了，感觉这样简单 -->
			<view
				class="pure-rate__half pure-rate__half--left"
				@tap="_handleClick(_i, 'left')"
				@touchstart.stop="_handleLeftTouchStart($event, _i, 'left')"
			></view>
			<view
				class="pure-rate__half pure-rate__half--right"
				@tap="_handleClick(_i, 'right')"
				@touchstart.stop="_handleRightTouchStart($event, _i, 'right')"
			></view>
		</view>
	</view>
</template>

<script>
	import commonComponentOptions from "../../config/options";
	export default {
		options: commonComponentOptions
	};
</script>

<script setup>
	import { ref, computed, getCurrentInstance, inject, watch } from "vue";
	import props from "./props";
	import { getRect, generateUUID } from "@/uni_modules/pure-utils";

	// -------------------------------------------------------------------------------- Refs
	const _instance = getCurrentInstance();
	const _uuid = ref(generateUUID());
	const _componentWidth = ref(0);

	// -------------------------------------------------------------------------------- Props
	const _props = defineProps(props);

	// -------------------------------------------------------------------------------- Emits
	const _emits = defineEmits(["update:modelValue"]);

	// -------------------------------------------------------------------------------- Classes
	const _classes = computed(() => {
		const array = [];

		// 是否禁用
		if (_props.disabled) array.push("pure-rate--disabled");

		// 是否只读
		if (_props.readonly) array.push("pure-rate--readonly");

		return array;
	});

	// -------------------------------------------------------------------------------- Styles
	const _styles = computed(() => {
		const array = [];

		// 默认颜色
		if (_props.defaultColor) array.push(`--pure-rate-icon-default-color: ${_props.defaultColor}`);

		// 填充颜色
		if (_props.fillColor) array.push(`--pure-rate-icon-fill-color: ${_props.fillColor}`);

		// 禁用颜色
		if (_props.disabledColor) array.push(`--pure-rate-icon-disabled-color: ${_props.disabledColor}`);

		return array;
	});

	// -------------------------------------------------------------------------------- Events
	// Item Classes
	function _calcItemClasses(i) {
		const array = [];

		// 是否选中整星
		if (Math.floor(_props.modelValue) >= i) array.push("pure-rate__item--full");

		return array;
	}

	// 是否显示填充图标
	function _showFillIcon(i) {
		return _props.modelValue > i - 1;
	}

	// 填充图标样式
	function _caleFillIconStyles(i) {
		const array = [];

		// 不允许半星
		if (!_props.allowHalf) {
			// 宽度
			if (i <= Math.floor(_props.modelValue)) array.push(`width: 100%`);
		}

		// 允许半星
		else {
			// 宽度
			if (i <= Math.floor(_props.modelValue)) array.push(`width: 100%`);
			else array.push(`width: ${(1 - (i - _props.modelValue)) * 100}%`);
		}

		return array;
	}

	// 点击事件
	function _handleClick(i, position) {
		// 不允许半星
		if (!_props.allowHalf) {
			// 允许清除
			if (_props.clearable && i === Math.floor(_props.modelValue)) {
				_emitUpdateModelValue(i - 1);
				return;
			}

			_emitUpdateModelValue(i);
			return;
		}

		// 允许半星
		// 左侧
		if (position === "left") {
			// 允许清除
			if (_props.clearable && _props.modelValue > i - 1 && _props.modelValue <= i - 0.5) {
				_emitUpdateModelValue(i - 1);
				return;
			}

			// 不允许清除
			_emitUpdateModelValue(i - 0.5);
			return;
		}

		// 右侧
		// 允许清除
		if (_props.clearable && _props.modelValue > i - 0.5 && _props.modelValue <= i) {
			_emitUpdateModelValue(i - 0.5);
			return;
		}

		// 不允许清除
		_emitUpdateModelValue(i);
		return;
	}

	// 触摸开始
	async function _handleTouchStart(e) {
		e.stopPropagation();
		e.preventDefault();
		if (!_props.touchable) return;
		const rect = await getRect(`#${_uuid.value}`, _instance.proxy);
		_componentWidth.value = rect?.width || 0;
		_calculateTouchScore(e.touches[0].clientX, e.currentTarget.offsetLeft);
	}

	// 触摸移动事件
	async function _handleTouchMove(e) {
		if (!_props.touchable) return;
		_calculateTouchScore(e.touches[0].clientX, e.currentTarget.offsetLeft);
	}

	// 触摸开始 - 左侧
	async function _handleLeftTouchStart(e, i, position) {
		e.stopPropagation();
		e.preventDefault();
		const rect = await getRect(`#${_uuid.value}`, _instance.proxy);
		_componentWidth.value = rect?.width || 0;
		_handleClick(i, position);
	}

	// 触摸开始 - 右侧
	async function _handleRightTouchStart(e, i, position) {
		e.stopPropagation();
		e.preventDefault();
		const rect = await getRect(`#${_uuid.value}`, _instance.proxy);
		_componentWidth.value = rect?.width || 0;
		_handleClick(i, position);
	}

	// 计算触摸后的分数
	// clientX： 触摸点距离屏幕左侧的距离
	// offsetLeft： 组件距离屏幕左侧的距离
	function _calculateTouchScore(clientX = 0, offsetLeft = 0) {
		if (_componentWidth.value === 0) return;

		// 触摸比例
		const touchRatio = (clientX - offsetLeft) / _componentWidth.value;

		// 换算成分数
		let score = touchRatio * _props.count;

		// 第几颗星星
		let i = Math.ceil(score);

		// 分数不能超出范围
		if (i > _props.count) i = _props.count;
		if (i < 0) i = 0;

		// 左侧还是右侧
		let position = "";
		if (score <= 0) position = "left";
		else if (score >= _props.count) position = "right";
		else position = score - Math.floor(score) > 0.5 ? "right" : "left";

		// 触发对应的点击事件
		_handleClick(i, position);
	}

	// 提交事件
	function _emitUpdateModelValue(score) {
		if (score < 0) score = 0;
		if (score > _props.count) score = _props.count;
		_emits("update:modelValue", score);
	}

	// -------------------------------------------------------------------------------- Injects
	const PureFormItemOnBlur = inject("PureFormItemOnBlur", null);
	const PureFormItemOnChange = inject("PureFormItemOnChange", null);

	// 触摸结束后触发失焦事件
	function _handleTouchEnd() {
		if (PureFormItemOnBlur) PureFormItemOnBlur();
	}

	// 分数变化后触发改变事件
	watch(
		() => _props.modelValue,
		() => {
			if (PureFormItemOnChange) PureFormItemOnChange();
		}
	);
</script>

<style scoped lang="scss">
	@import "./style.scss";
</style>
